home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr05
/
xnot12a.zip
/
W3WIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-16
|
44KB
|
1,532 lines
#ifdef MSW /** WHOLE FILE **/
/*
This is a quickie port of MG2a (MicroEMACS derived) to MsWindows 3.1.
The original code ran under DOS to a bios interface
with direct hardware access to the keyboard and system clock. This
version and the following w3 files have been (mostly) hooked in underneath
the original code, which thankfully had most of the terminal io (screen
access) and keyboard input at a level distinct from the core editor. Not
every function is relegated to the absolute best .C file location (for
example, a system call is implemented inside w3win.c since it is, after
all, a WinExec call.... In addition, much bashing was done to make
this Emacs look more like GNU-Emacs (make/next-error functions), automatic
timed backups, timestamp checking, and a large assortment of functions
implemented to extend the editor and move it away from MicroEMACS to
GNU-emacs feel. It's a reasonable result given the amount of time spent. :)
The goal was not to make emacs window-aware. Instead, the window specific
code was to act like a terminal. That is why the startup code (windows code)
executes first; to create a window, etc such that when EmaxMain is called,
the 'terminal' (ie window) exists. The input handling is done by creating
an internal queue at the 'terminal' level and emacs just reads chars from
the 'keyboard' buffer. Special window-specific things happen without core
code being aware (ie focus events, etc). Events which require a core code
response, like window resize, generate emacs recognizable keycodes (or
entire command strings) which the editor can get. Resize in specific
generates redraw-display and the core code already did a terminal size
query for that command.
Mouse events are funny; window specific code handles them as far as
determining double click, etc. But window level code only goes as far
as converting mouse events to emacs commands for left, right, up/down,
etc. In other words, emacs is now mouse-aware, but in an abstract way.
A wayward user can use the keyboard to send mouse actions, though not
easily. Only window level code can parse a mouse click/motion to rows
and columns that emacs needs. This is based on font, window size, etc.
I'm considering making the DOS version support the mouse since most
of the code is there; just a couple of things to hook to the mouse.
(Could also do the system clock for time, auto backups, etc but I don't
want to kill Windows and I have to figure out how to get the interrupt
w/o zapping Windows so gnu would run safely in a DOS window. Same
cavet goes with making DOS-gnu use XMS.)
Things to make better: foremost is the desire of the core editor to
write a single character at a time; and the windows level implementation is
being faithful to that request BUT it really should cache some consecutive
characters when it can! (DONE!) Next would be a cleanup of the ifdef's, and
re-org of function-to-file mapping.
w3 source files:
jam.h version defines, includes, etc
w3win.c (this file) main, event loop, window proc, window creation, etc
w3io.c (aka ttyio.c) character output, scrolling, etc
w3key.c map keypress event to some EMACS virtual key for
extended commands
w3font.c support for fonts, emax.ini file support
w3mem.c 32 bit global memory mangler
w3ext.c support for drag&drop, print, cut/copy/paste (to
Window's clipboard)
dos.c not windows really, but new dos things
*/
#define W3WIN_C /* prevent multiple define of globals */
#include "jam.h"
#include "windowsx.h" /* windows/nt extension macros */
#include "def.h"
#include "keyname.h"
#include "stdio.h"
#include "ttydef.h"
#include "chrdef.h"
#include "malloc.h"
#include "time.h"
#include "commdlg.h" /* font and open/save file dialogs */
#include "shellapi.h" /* drag & drop */
extern void FAR _cdecl exit(int); /* to keep compiler happy */
/* Globals, externed in jam.h
*/
HANDLE g_hInstance;
HWND g_hWnd = 0; /* the 1 and only window */
HDC g_hDC;
int g_nLineHeight, g_nCharWidth;
UINT g_idTimer = 0;
int g_caret_x = -1, g_caret_y = -1;
HFONT g_hfont = 0;
HFONT g_oldFont = 0;
BOOL g_caret = FALSE;
BOOL g_update = FALSE;
BOOL edInited = FALSE;
BOOL g_hasFocus = FALSE;
BOOL g_menu = FALSE;
/* Misc contants
*/
#define FONT_CHOICE 100 /* menu ids for system menu */
#define ABOUT_CHOICE 110
#define SAVE_CHOICE 120
#define TOGGLE_CHOICE 130
#define ABORT_CHOICE 140
#define COLORS_CHOICE 150
/* pullrights...
*/
#define TCOLOR_CHOICE 200
#define WCOLOR_CHOICE 210
#define CCOLOR_CHOICE 220 /* changes color */
#define OPEN_CHOICE 300 /* menu ids for main window menu */
#define OPEN_CHOICE2 310
#define INSERT_CHOICE 320
#define REVERT_CHOICE 330
#define SAVEAS_CHOICE 340
#define PRINT_CHOICE 350
#define COPY_CHOICE 360 /* clipboard functions */
#define CUT_CHOICE 370
#define PASTE_CHOICE 380
#define HELP_APROPOS 390
#define HELP_ABOUT 400
#define KEXTEND_CHOICE 500 /* menu ids for main window menu */
#define LEFT 0x1
#define RIGHT 0x2
/* Local statics
*/
#ifdef WIN32
# include <winbase.h>
static STARTUPINFO s_sInfo = { 0 };
static PROCESS_INFORMATION s_pInfo = { 0 };
#else
static HWND s_appwindow = 0;
#endif
static int s_scrollTicks = 0; /* autoscroll */
static HCURSOR s_loadedcursor = 0;
static BOOL s_waitingforapp = FALSE;
static BOOL s_fatal = FALSE;
static int s_btndown = 0;
static int s_sleep = 0;
static int s_sTicks = 0; /* inc-save interval */
static HRGN s_hrgn = 0;
static char s_timestr[35] = {0};
static char *s_APPNAMEQUESTION = AppQuestion;
static char *s_APPNAMEMSG = AppMsg;
static char *APPCLASS = "MyToy Class";
static char *curname = 0;
static char *blank = " ";
static char s_spawnbuf[NFILEN];
/* Array of pulldown menus.
*/
#define PARENT 0
#define FILEM 1
#define EDITM 2
#define WINDOWM 3
#define EXECM 4
#define HELPM 5
#define NUMBERM 6
#define FreeLoadedCursor(c)\
if (c)\
{\
DestroyCursor(c);\
c = 0;\
}
static HMENU s_menu[NUMBERM];
static UINT s_choices = 0;
/* Local function prototypes
*/
BOOL FAR PASCAL findWindow(HWND hWnd, LONG lParam);
static void SetTheTitle(void);
static void WindowAddMenu(void);
static void getthetime(void);
static void DoMenuThing(void);
static void chooseColor(WPARAM wParam);
static void ReverseCaret(void);
BOOL WindowFatalState(void)
{
return(s_fatal);
}
/* Set window title as appropriate.
*/
static void SetTheTitle()
{
char buffer[200], dir[100];
static char lastTitle[200] = {0};
strcpy(buffer, g_APPNAME);
strcat(buffer, " ");
/* short vs long title
*/
if (!IsIconic(g_hWnd) && wdir)
{
strcat(buffer, shortversion());
strcpy(dir, wdir);
adjustnamecase(dir);
strcat(buffer, " (");
strcat(buffer, dir);
strcat(buffer, ") ");
}
strcat(buffer, s_timestr); /* update when needed */
if (strcmp(buffer, lastTitle) != 0)
{
SetWindowText(g_hWnd, buffer);
strcpy(lastTitle, buffer); /* save last time */
}
}
/* Update the time string, used for window title
*/
static void getthetime(void)
{
long currtime;
struct tm *timestruct;
BOOL am = TRUE;
int hour;
time(&currtime);
timestruct = localtime(&currtime);
hour = timestruct->tm_hour;
if (hour > 12)
{
hour -= 12;
am = FALSE;
}
sprintf(s_timestr, " %d:%02d%s\0",
hour, timestruct->tm_min, am ? "am" : "pm");
}
/*
* WinMain
*
* Arguments:
*
* hInstance - handle of this instance of notgnu.exe
* hPrevInstance - handle to a previous instance
* lpCmdLine - string containing command line arguments
* nCmdShow - argument to ShowWindow that controls how
* Windows would like to start this application.
*
* Return value:
*
* an integer with the final result of the application
*/
int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HANDLE hInstance;
HANDLE hPrevInstance;
LPSTR lpCmdLine;
int nCmdShow;
{
int argc = 0;
#define NARGS 50
char *argv[50], *p;
WNDCLASS wc;
char progname[NFILEN];
DWORD flags;
/* who are we?
*/
if (!GetModuleFileName(hInstance, progname, NFILEN))
progname[0] = '\0';
/* first thing to do is init the internal heap manager
* and the message queue
*/
#ifndef WIN32
W3memLocalInitialize();
/* Set the max size of the message queue; default is 8.
*/
{
int queue_size = 300;
while (!SetMessageQueue(queue_size--))
;
}
#endif
/*
* Move some of the arguments into global variables so that
* editor can use them later.
*/
g_hInstance = hInstance;
/*
* Set up argc and argv.
*/
argv[argc++] = progname;
p = lpCmdLine;
/* Gather file names
*/
if (argc >= NARGS)
{
/* printf("Number of input args too large! Truncating to %d\n", NARGS); */
argc = NARGS - 1;
}
while(p && *p)
{
while (*p && ISWHITE(*p)) /* get to start of this param */
p++;
argv[argc++] = p;
while (*p && !ISWHITE(*p)) /* get to end of this param */
p++;
/* properly terminate it for 'main'
*/
if (ISWHITE(*p)) /* more stuff may follow */
{
*p = '\0';
p++;
}
}
/* Fill in window class structure with parameters that describe the
* main window. Only need to do this if no previous task did it..
*/
if (!hPrevInstance)
{
wc.style = CS_DBLCLKS; /* Class style(s). */
wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages */
wc.cbClsExtra = 0; /* No per-class extra data.*/
wc.cbWndExtra = 0; /* No per-window extra data.*/
wc.hInstance = hInstance; /* Application that owns the class.*/
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.hIcon = LoadIcon(hInstance, "ID_NOTICON");
wc.lpszClassName = APPCLASS; /* Name used in call to CreateWindow. */
/* Register the window class and check success/failure code.
*/
if (!RegisterClass(&wc))
{
WindowMessage("Failed to create window class!", FALSE);
return(FALSE);
}
}
/* create a window
*/
flags = WS_OVERLAPPEDWINDOW;
#ifdef VBAR
flags |= WS_VSCROLL;
#endif
g_hWnd = CreateWindow(APPCLASS, g_APPNAME, flags,
CW_USEDEFAULT, /* Default horizontal position.*/
CW_USEDEFAULT, /* Default vertical position. */
CW_USEDEFAULT, /* Default width. */
CW_USEDEFAULT, /* Default height.*/
NULL, /* Overlapped windows have no parent.*/
NULL, /* Use the window class menu. */
hInstance,
NULL /* Pointer not needed. */
);
/* If window could not be created, return "failure"
*/
if (!g_hWnd)
{
WindowMessage("Failed to create window!", FALSE);
return(FALSE);
}
/* Init internal input buffer(s)
*/
InitInput();
/* Grab the hdc, get a default font
*/
g_hDC = GetDC(g_hWnd);
SetBkMode(g_hDC, OPAQUE);
WindowInitFont(FONTSIZE);
/* Size window based on font, find menubar setting
*/
InitWindow(START_COLS, START_LINES);
UpdateWindow(g_hWnd);
/* Make the window visible; update its client area
* and add things to default system menu
*/
ShowWindow(g_hWnd, nCmdShow);
ttresize();
s_menu[PARENT] = (HMENU)0;
WindowAddMenu();
DragAcceptFiles(g_hWnd, TRUE); /* allow some drag/drop stuff */
/*
* Call 'main' body of editor
*/
edInited = TRUE; /* any message after this is ok to process */
if (newUser())
MakeBanner();
EmaxMain(argc, argv); /* return from here is exit editor */
/* Free resources
*/
if (g_idTimer)
KillTimer(g_hWnd, g_idTimer); /* Stops the timer */
if (g_hfont)
{
SelectObject(g_hDC, g_oldFont);
DeleteObject(g_hfont);
}
ReleaseDC(g_hWnd, g_hDC);
if (s_menu[0])
{
SetMenu(g_hWnd, 0);
DestroyMenu(s_menu[0]);
}
DestroyWindow(g_hWnd);
/* Cleanup the heap. Any memory not free-ed gets released
* since part of managed heap.
*/
#ifndef WIN32
W3memLocalTerminate();
#endif
return 1;
}
/* Pending event during screen refresh?
*/
BOOL WindowLookaheadEvent(void)
{
MSG msg;
if (PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
return(TRUE);
if (PeekMessage(&msg, NULL, WM_SIZE, WM_SIZE, PM_NOREMOVE))
return(TRUE);
return(FALSE);
}
/* Return a cached event; wait if none pending.
*/
void WindowGetEvent(void *ptr)
{
MSG msg;
BOOL result;
/* Make sure something is there
*/
for (result = FALSE; !result; )
if (!(result = WindowReturnKCHAR((KCHAR *)ptr)))
{
/* See if Windows has any; process and return if
* result of Windows event yields a KCHAR, or if
* other KCHARs were waiting.
*
* Cursor on during wait...
*/
if (IsCaretCreated() && (s_btndown == 0))
SetCaretVis(TRUE);
if (GetMessage(&msg, NULL, NULL, NULL))
{
/* Cursor off during processing
*/
if (IsCaretCreated())
SetCaretVis(FALSE);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
/* Dump a string to a message box. If fatal,
* leave ungracefully...
*/
void WindowMessage(s, fatal)
char *s;
BOOL fatal;
{
BOOL wasVis;
if (wasVis = IsCaretVis())
SetCaretVis(FALSE);
MessageBox(0, s, s_APPNAMEMSG, MB_OK | MB_APPLMODAL);
if (wasVis)
SetCaretVis(TRUE);
if (fatal)
{
s_fatal = TRUE;
ealtmsg = TRUE;
IncrementalSave();
exit(1);
}
}
/* Simple-minded stub to exec something
*/
int winspawn(char *s, BOOL windows)
{
char buf[NLINE];
BOOL sync;
#ifdef WIN32
char *sh = "cmd.exe";
#else
char *sh = "command.com";
FARPROC proc;
int appHandle;
#endif
sync = FALSE;
/* From 'shell-window' command (create a shell window)
*/
if (!s) /* lack of command string implies shell window */
{
#ifdef WIN32
strcpy(buf, sh);
#else
strcpy(buf, apppath());
strcat(buf, "meshell.pif");
if (!fileisok(buf)) /* is 'our' shell here? */
strcpy(buf, sh); /* default shell */
#endif
}
/* From 'shell-command' or 'window-command' (spawn background job)
*/
else if (s_waitingforapp && !windows)
{
/* Feeble - should be able to spawn multiple background
* processes, but I'm not managing multiple logs...
*/
ewprintf("Pending shell-command already running in background.");
return (FALSE);
}
/* build command string
*/
else
{
if (windows)
strcpy(buf, s);
else
{
/* destroy log first so won't read old log by accident
*/
strcpy(buf, dirpath());
strcat(buf, spawnfilename);
unlink(buf);
strcpy(buf, sh);
strcat(buf, " /c ");
strcat(buf, s);
strcat(buf, " > ");
strcat(buf, spawnfilename);
sync = TRUE;
/* create name for reading in after
* task completes
*/
strcpy(s_spawnbuf, dirpath());
strcat(s_spawnbuf, spawnfilename);
}
}
#ifdef WIN32
ewprintf("CreateProcess: %s", buf);
s_sInfo.cb = sizeof(STARTUPINFO);
s_sInfo.lpTitle = AppJob;
s_sInfo.wShowWindow = (sync ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL);
s_sInfo.dwFlags = STARTF_USESHOWWINDOW;
if (CreateProcess(NULL, buf, NULL, NULL, DETACHED_PROCESS,
FALSE, NULL, NULL, &s_sInfo, &s_pInfo))
{
if (sync)
s_waitingforapp = TRUE;
}
else
{
sprintf(buf, "CreateProcess error: %s", buf);
WindowMessage(buf, FALSE);
ewprintf(blank);
noop();
return (FALSE);
}
#else
ewprintf("WinExec: %s", buf);
SetCaretVis(FALSE);
appHandle = WinExec(buf, sync ? SW_SHOWMINNOACTIVE : SW_SHOW);
if (appHandle < 32) /* error */
{
sprintf(buf, "WinExec error %d", appHandle);
WindowMessage(buf, FALSE);
ewprintf(blank);
noop();
return (FALSE);
}
else if (sync)
{
/* job running, find window handle to wait for completion
*/
proc = MakeProcInstance((FARPROC)findWindow, g_hInstance);
EnumWindows(proc, (DWORD)appHandle);
FreeProcInstance(proc);
if (s_appwindow != 0)
s_waitingforapp = TRUE;
}
#endif
noop();
return(TRUE);
}
/*
* Main window procedure for the one and only window
* we create.
*/
long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
int status;
char buff[40];
int downcol, downrow;
int cmd_param;
switch (message)
{
case WM_CREATE:
g_idTimer = SetTimer(hWnd, NULL, TIME_INC, (FARPROC) NULL);
break;
case WM_DROPFILES:
HandleDroppedFiles((HANDLE)wParam); /* w3ext.c */
break;
case WM_TIMER:
if (edInited)
{
static int tTicks = 0; /* title update interval */
/* Any messages printed by routines called
* from a WM_TIMER message must not use standard
* output method.
*/
ealtmsg = TRUE;
/* Counter for titlebar update; also use this increment to
* check for spawned shells
*/
tTicks++;
if (tTicks > INCS_PER_UPDATE)
{
getthetime(); /* get current clock time */
SetTheTitle(); /* fix window title */
tTicks = 0;
/* Spawned app running?
*/
#ifdef DOGRINDER
if (!s_btndown && s_waitingforapp)
WindowGrinderCursor();
#endif
#ifdef WIN32
if (!isearching && !eprompting && !s_btndown &&
(s_waitingforapp &&
!(WaitForSingleObject(s_pInfo.hProcess, 0) == WAIT_TIMEOUT)))
{
CloseHandle(s_pInfo.hThread);
CloseHandle(s_pInfo.hProcess);
#else
if (!isearching && !eprompting && !s_btndown &&
(s_waitingforapp && !IsWindow(s_appwindow)))
{
#endif
s_waitingforapp = FALSE;
ttbeep();
#ifdef DOGRINDER
WindowNormalCursor();
#endif
status = MessageBox(0, "Shell command completed, read log?",
s_APPNAMEQUESTION,
MB_YESNO | MB_APPLMODAL | MB_ICONQUESTION);
if (status == IDYES)
{
BUFFER *bp = bfind(spawnfilename, FALSE);
/* Nuke any old logs from different dirs
*/
if (bp)
{
bp->b_flag &= ~BFCHG;
if (strcmp(bp->b_fname, s_spawnbuf) != 0)
nukebuffer(bp);
}
#if 1
ExtendedFunction(function_name(poptofilequiet));
AddString(s_spawnbuf);
AddKchar(CCHR('J'));
#else
AddString(s_spawnbuf);
AddKchar(CCHR('J'));
poptofilequiet(0, 1); /* go get it */
ExtendedFunction(function_name(donothing));
/* Mark the file to be deleted when buffer is
* nuked
*/
if (bp = bfind(spawnfilename, FALSE))
bp->b_flag |= BFDELETE;
#endif
}
}
/* Any user defined alarms to execute?
*/
{
static BOOL incallback = FALSE;
if (!incallback)
{
incallback = TRUE;
AnyPendingAlarms();
incallback = FALSE;
}
}
} /* incs per update */
/* Auto scroll current window if left button
* down and control key is also
*/
if ((s_btndown & LEFT) && (GetKeyState(VK_CONTROL) < 0))
{
s_scrollTicks++;
if (s_scrollTicks >= DELAY_TO_SCROLL)
{
char buff[8];
ExtendedFunction(function_name(mousecmd));
AddString(MouseTimer);
sprintf(buff, " %d ", GetKeyState(VK_SHIFT) < 0 ? 1: 0);
AddString(buff);
s_scrollTicks = DELAY_TO_SCROLL; /* prevent overflow */
}
}
else
s_scrollTicks = 0; /* force reset */
/* Counter for incremental save (keyboard input delays this)
* and pending prompt postpones this indefinitly!!!
*/
s_sTicks++;
if ((s_sTicks > INCS_PER_SAVE) && !eprompting)
{
static BOOL incallback = FALSE;
if (!incallback)
{
incallback = TRUE;
IncrementalSave(); /* autosave in file.c */
incallback = FALSE;
s_sTicks = 0;
}
}
ealtmsg = FALSE;
}
break;
case WM_SYSCOLORCHANGE:
return (0); /* basically ignored. */
case WM_SYSCOMMAND:
switch (wParam)
{
case FONT_CHOICE:
WindowNewFont();
break;
case ABOUT_CHOICE:
MakeBanner();
break;
case SAVE_CHOICE:
SaveAllSettings();
break;
case TOGGLE_CHOICE:
togglemenu(0, 1);
break;
case ABORT_CHOICE:
status = MessageBox(0, "Shoot me dead now?\n (This is equal to a crash!)",
s_APPNAMEQUESTION, MB_YESNO | MB_APPLMODAL |
MB_ICONSTOP);
if (status == IDYES)
ExtendedFunction(function_name(shootmedead));
break;
case TCOLOR_CHOICE:
case WCOLOR_CHOICE:
case CCOLOR_CHOICE:
chooseColor(wParam);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_SETFOCUS:
#ifdef WINDOWS_CURSOR
CreateCaret(hWnd, NULL, g_nCharWidth, g_nLineHeight);
SetCaretPos(g_caret_x, g_caret_y);
#endif
SetCaretCreated(TRUE);
g_hasFocus = TRUE;
break;
case WM_KILLFOCUS:
SetCaretVis(FALSE);
#ifdef WINDOWS_CURSOR
DestroyCaret();
#endif
SetCaretCreated(FALSE);
g_hasFocus = FALSE;
break;
#ifdef VBAR /* never completed, not 1/buffer, etc */
case WM_VSCROLL:
if (edInited)
switch(wParam)
{
case SB_TOP:
ExtendedFunction(function_name(gotobob));
break;
case SB_BOTTOM:
ExtendedFunction(function_name(gotoeob));
break;
case SB_LINEUP:
ExtendedFunction(function_name(back1page));
break;
case SB_LINEDOWN:
ExtendedFunction(function_name(forw1page));
break;
case SB_PAGEUP:
ExtendedFunction(function_name(backpage));
break;
case SB_PAGEDOWN:
ExtendedFunction(function_name(forwpage));
break;
default:
noop();
}
break;
#endif
case WM_RBUTTONDOWN:
GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
s_btndown |= RIGHT;
ExtendedFunction(function_name(mousecmd));
if (s_btndown & LEFT)
{
AddString(MouseAbort);
AddKchar(' ');
}
else
{
AddString(RightDwn);
sprintf(buff, posFormat, downrow, downcol);
AddString(buff);
}
break;
case WM_RBUTTONUP:
if (s_btndown & RIGHT) /* was it down in our window?? */
s_btndown &= ~RIGHT;
noop();
break;
case WM_MOUSEMOVE:
GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
if ((s_btndown & LEFT) && !(s_btndown & RIGHT))
{
s_scrollTicks = 0; /* stop autoscroll */
ExtendedFunction(function_name(mousecmd));
AddString(MoveStr);
sprintf(buff, posFormat, downrow, downcol);
AddString(buff);
}
break;
#if 1 /* there is a redraw marker bug :( */
case WM_MOUSEACTIVATE:
return (MA_ACTIVATEANDEAT);
#endif
case WM_LBUTTONDOWN:
GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
s_btndown |= LEFT;
ExtendedFunction(function_name(mousecmd));
if (s_btndown & RIGHT)
{
AddString(MouseAbort);
AddKchar(' ');
}
else
{
if (wParam & MK_SHIFT)
AddString(LeftDwnShift);
else
AddString(LeftDwn);
sprintf(buff, posFormat, downrow, downcol);
AddString(buff);
SetCapture(g_hWnd);
}
break;
case WM_LBUTTONUP:
GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
if (s_btndown & LEFT) /* was it down in our window?? */
{
s_btndown &= ~LEFT;
ExtendedFunction(function_name(mousecmd));
AddString(LeftUp);
sprintf(buff, posFormat, downrow, downcol);
AddString(buff);
ReleaseCapture();
}
break;
case WM_LBUTTONDBLCLK:
GetRowCol(&downrow, &downcol, LOWORD(lParam), HIWORD(lParam));
if ((s_btndown & RIGHT) == 0)
{
ExtendedFunction(function_name(mousecmd));
AddString(DoubleClick);
AddKchar(' ');
}
else
{
AddString(MouseAbort);
AddKchar(' ');
}
ReleaseCapture();
break;
case WM_COMMAND:
cmd_param = (int)LOWORD(wParam);
if ((cmd_param >= KEXTEND_CHOICE) && (cmd_param <= (int)s_choices))
{
char cmd[NLINE + 1];
register int i;
/* This hacky loop let me move menu items anywhere I
* wanted w/o having to know which pulldown it belonged to (or
* care for that matter). All 'extendable' functions have an
* id between KEXTEND_CHOICE and s_choices (s_choices is incremented
* after each moveable, extendable menu item is added). Ok, so it's
* a little ughly, but it was quick and easy!
*/
for (i = 1; i <= NUMBERM; i++)
if (GetMenuString(s_menu[i], cmd_param, cmd, NLINE,
MF_BYCOMMAND) > 0)
{
ExtendedFunction(cmd);
break;
}
}
else /* special case pre-processed events */
switch(cmd_param)
{
case HELP_APROPOS:
ExtendedFunction(function_name(apropos_command));
AddKchar('a');
AddKchar(CCHR('J'));
break;
case HELP_ABOUT:
MakeBanner();
break;
case COPY_CHOICE:
case CUT_CHOICE:
HandleCutCopy(cmd_param == CUT_CHOICE ? TRUE : FALSE);
break;
case PASTE_CHOICE: /* NOTE Not dimming choices yet! */
HandlePaste();
break;
#ifdef DOPRINT
case PRINT_CHOICE:
HandlePrint();
break;
#endif
case OPEN_CHOICE:
case INSERT_CHOICE:
case OPEN_CHOICE2:
case SAVEAS_CHOICE:
{
OPENFILENAME openfile;
char fname[NFILEN+1];
BOOL result = FALSE;
memset(fname, '\0', sizeof(fname));
memset(&openfile, '\0', sizeof(OPENFILENAME));
strcpy(fname, "*.c;*.h;*.txt");
openfile.lStructSize = sizeof(openfile);
openfile.lpstrFilter = "*.*";
openfile.lpstrFile = fname;
openfile.nMaxFile = sizeof(fname);
if (cmd_param == SAVEAS_CHOICE)
openfile.Flags = OFN_OVERWRITEPROMPT;
openfile.Flags |= OFN_PATHMUSTEXIST;
openfile.Flags |= OFN_HIDEREADONLY;
EnableWindow(g_hWnd, FALSE);
if (cmd_param == SAVEAS_CHOICE)
result = GetSaveFileName(&openfile);
else
result = GetOpenFileName(&openfile);
EnableWindow(g_hWnd, TRUE);
SetActiveWindow(g_hWnd);
if (result)
{
disable_preload(); /* full name already supplied */
if (cmd_param == OPEN_CHOICE)
ExtendedFunction(function_name(filevisit));
else if (cmd_param == OPEN_CHOICE2)
ExtendedFunction(function_name(poptofile));
else if (cmd_param == SAVEAS_CHOICE)
ExtendedFunction(function_name(filewrite));
else
ExtendedFunction(function_name(fileinsert));
AddString(fname);
AddKchar(CCHR('J'));
}
}
default:
break;
}
break;
case WM_SYSKEYDOWN:
case WM_SYSCHAR:
case WM_CHAR:
case WM_KEYDOWN:
if (edInited)
{
/* SPECIAL CASE TO ALLOW TASK SWITCHING AND ACCESS
* TO SYSTEM MENU
*/
if ((message == WM_SYSKEYDOWN) && (wParam == VK_TAB))
return (DefWindowProc(hWnd, message, wParam, lParam));
if ((message == WM_SYSCHAR) && (wParam == ' '))
return (DefWindowProc(hWnd, message, wParam, lParam));
/* Regular input events cause some delay to autosave
*/
s_sTicks -= SAVE_DELAY;
if (s_sTicks < 0)
s_sTicks = 0;
/* Prevent garbled commands interrupting mouse
*/
if (!s_btndown)
WindowMapKey(message, wParam, lParam);
}
break;
case WM_PAINT:
{
HDC hDC;
PAINTSTRUCT ps;
RECT r;
/* satisfy windows, get the update region
*/
hDC = BeginPaint (hWnd, &ps);
r = ps.rcPaint;
EndPaint(hWnd, &ps);
/* Draw...
*/
if (!IsIconic(g_hWnd) && edInited)
{
int row = ttrow;
int col = ttcol;
sgarbf = TRUE;
s_hrgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
SelectClipRgn(g_hDC, s_hrgn);
/* Fix in-progress stuff after redraw; in all cases
* some event gets into the input queue to get the
* cursor updated after processing. Not pretty!
*/
update();
if (isearching)
noop(); /* jumpSearch(); hacky research to refresh */
else if (eprompting)
erepair(); /* fix prompt+msg */
else
ExtendedFunction(function_name(donothing));
SelectClipRgn(g_hDC, NULL);
DeleteObject(s_hrgn);
ttmove(row, col); /* restore cursor */
}
break;
}
case WM_SIZE:
if (!IsIconic(g_hWnd))
{
if (edInited)
{
RECT rect;
GetClientRect(g_hWnd, &rect);
ValidateRect(g_hWnd, &rect);
ExtendedFunction(function_name(myrefresh));
}
}
SetTheTitle();
break;
case WM_QUERYENDSESSION:
if (!anycb(ABORT))
{
ExitCleanup(); /* cleanup work files */
return(1); /* all clear to exit */
}
/* Modified files, tell user and request dispostion (love them
* big words!)
*/
ShowWindow(g_hWnd, SW_SHOW);
status = MessageBox(0, "Saved modified buffers?", s_APPNAMEQUESTION,
MB_YESNOCANCEL | MB_SYSTEMMODAL | MB_ICONQUESTION);
if (status == IDNO)
{
ExitCleanup(); /* cleanup work files */
return(1); /* let windows go */
}
else if (status == IDYES)
{
savebuffers(TRUE, 0);
ExitCleanup(); /* cleanup work files */
return(1);
}
break;
case WM_CLOSE:
ExtendedFunction(function_name(quit));
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (NULL);
}
/* find row col from pos
*/
void GetRowCol(int *prow, int *pcol, int x, int y)
{
register int row, col;
col = (x + 1)/g_nCharWidth;
row = (y + 1)/g_nLineHeight;
if (col < 0)
col = 0;
else if (col > ncol)
col = ncol;
if (row < 0)
row = 0;
else if (row > nrow)
row = nrow;
*pcol = col;
*prow = row;
}
/* add things to system menu
*/
static void WindowAddMenu(void)
{
HMENU sysmenu = (HMENU) 0;
HMENU pop;
/* return Window's default menu
*/
if (!(sysmenu = GetSystemMenu(g_hWnd, FALSE)))
{
WindowMessage("Can't add to system menu!", FALSE);
return;
}
AppendMenu(sysmenu, MF_SEPARATOR, 0, 0L);
AppendMenu(sysmenu, MF_STRING, TOGGLE_CHOICE, "Window Men&u");
AppendMenu(sysmenu, MF_STRING, FONT_CHOICE, "&Font...");
/* Choice + pullright
*/
pop = CreateMenu();
AppendMenu(sysmenu, MF_ENABLED|MF_POPUP, (UINT)pop, "C&olors");
AppendMenu(pop, MF_STRING, TCOLOR_CHOICE, "&Text Color...");
AppendMenu(pop, MF_STRING, CCOLOR_CHOICE, "T&ouched Text Color...");
AppendMenu(pop, MF_STRING, WCOLOR_CHOICE, "&Window Color...");
AppendMenu(sysmenu, MF_STRING, SAVE_CHOICE, "&Save Settings");
AppendMenu(sysmenu, MF_SEPARATOR, 0, 0L);
AppendMenu(sysmenu, MF_STRING, ABOUT_CHOICE, "&About...");
AppendMenu(sysmenu, MF_STRING, ABORT_CHOICE, "Shoot Me &Dead!");
}
/* Draw cursor; s_cur_* set on draw, used on un-draw.
* Needed because ttmove moves g_caret_* w/o turning
* off caret.
*/
static int s_cur_x, s_cur_y;
void DoShowCaret(HANDLE hwnd)
{
MakeCaretVis(TRUE);
s_cur_x = g_caret_x;
s_cur_y = g_caret_y;
#ifdef WINDOWS_CURSOR
ShowCaret(hwnd);
#else
ReverseCaret();
#endif
}
/* Erase cursor
*/
void DoHideCaret(HANDLE hwnd)
{
MakeCaretVis(FALSE);
#ifdef WINDOWS_CURSOR
HideCaret(hwnd);
#else
ReverseCaret();
#endif
}
/* Cursor engine stuff if non-windows caret
*/
static void ReverseCaret()
{
RECT rect;
rect.left = s_cur_x;
rect.top = s_cur_y;
rect.bottom = rect.top + g_nLineHeight;
rect.right = rect.left + g_nCharWidth;
InvertRect(g_hDC, &rect);
}
/* Manage pointer switching for some operations
*/
void WindowSizeCursor(void)
{
HCURSOR cursor = LoadCursor(NULL, IDC_SIZENS);
if (cursor)
SetCursor(cursor);
}
void WindowDragCursor(void)
{
HCURSOR cursor = LoadCursor(NULL, IDC_IBEAM);
if (cursor)
SetCursor(cursor);
}
void WindowArrowCursor(void)
{
FreeLoadedCursor(s_loadedcursor);
s_loadedcursor = LoadCursor(g_hInstance, "ID_HANDE");
if (s_loadedcursor)
SetCursor(s_loadedcursor);
else
ewprintf("Can't load hand cursor.");
}
void WindowSleepCursor(void)
{
HCURSOR cursor = LoadCursor(NULL, IDC_WAIT);
if (cursor)
SetCursor(cursor);
}
#ifdef DOGRINDER
void WindowGrinderCursor(void)
{
char buff[100];
static firstfailure = TRUE;
HCURSOR saved = s_loadedcursor;
s_sleep++; /* check for wrap */
if (s_sleep > 8) /* hard coded numbers, ick! */
s_sleep = 1;
sprintf(buff, "ID_GRINDER%d", s_sleep);
s_loadedcursor = LoadCursor(g_hInstance, buff);
if (s_loadedcursor)
SetCursor(s_loadedcursor);
else
{
if (firstfailure)
ewprintf("Can't load sleep cursor");
firstfailure = FALSE;
}
FreeLoadedCursor(saved);
}
#endif
void WindowNormalCursor(void)
{
HCURSOR cursor = LoadCursor(NULL, IDC_ARROW);
if (cursor)
{
SetCursor(cursor);
/* check for old special cursor lying around
*/
FreeLoadedCursor(s_loadedcursor);
}
s_sleep = 0;
}
#ifndef WIN32
/* Used to find the shell window created when
* a background job was spawned. On NT, use the
* real process id
*/
BOOL FAR PASCAL findWindow(HWND hWnd, LONG lParam)
{
if (GetWindowInstance(hWnd) == (HINSTANCE)lParam)
{
s_appwindow = hWnd;
return FALSE; /* found it, stop enumerating */
}
return TRUE;
}
#endif
/* toggle existance of application menu bar
*/
int togglemenu(int f, int n)
{
g_menu = (g_menu ? FALSE: TRUE);
DoMenuThing();
return TRUE;
}
/* This is the application window menubar - as opposed
* to the system menu on the window
*/
static void DoMenuThing()
{
/* normal app menu?
*/
if (!g_menu)
SetMenu(g_hWnd, 0);
else if (g_menu)
{
if (s_menu[PARENT] == (HMENU)0)
{
HMENU pop;
s_choices = KEXTEND_CHOICE;
/* FILE (note open commands unique id)
*/
s_menu[PARENT] = CreateMenu();
pop = s_menu[FILEM] = CreatePopupMenu();
AppendMenu(pop, MF_STRING, OPEN_CHOICE, function_name(filevisit));
AppendMenu(pop, MF_STRING, OPEN_CHOICE2, function_name(poptofile));
AppendMenu(pop, MF_STRING, INSERT_CHOICE, function_name(fileinsert));
AppendMenu(pop, MF_STRING, s_choices++, function_name(filesave));
AppendMenu(pop, MF_STRING, SAVEAS_CHOICE, function_name(filewrite));
AppendMenu(pop, MF_STRING, s_choices++, function_name(savebuffers));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, REVERT_CHOICE, function_name(reverto));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, s_choices++, function_name(quit));
#ifdef DOPRINT
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, PRINT_CHOICE, (LPCSTR)"Print...");
#endif
AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP,
(UINT)pop, (LPCSTR)"File");
/* EDIT
*/
pop = s_menu[EDITM]= CreatePopupMenu();
AppendMenu(pop, MF_STRING, s_choices++, function_name(forwsearch));
AppendMenu(pop, MF_STRING, s_choices++, function_name(backsearch));
AppendMenu(pop, MF_STRING, s_choices++, function_name(queryrepl));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, s_choices++, function_name(setmark));
AppendMenu(pop, MF_STRING, s_choices++, function_name(swapmark));
AppendMenu(pop, MF_STRING, s_choices++, function_name(killregion));
AppendMenu(pop, MF_STRING, s_choices++, function_name(copyregion));
AppendMenu(pop, MF_STRING, s_choices++, function_name(yank));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, s_choices++, function_name(definemacro));
AppendMenu(pop, MF_STRING, s_choices++, function_name(finishmacro));
AppendMenu(pop, MF_STRING, s_choices++, function_name(executemacro));
AppendMenu(pop, MF_STRING, s_choices++, function_name(extend));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, CUT_CHOICE, (LPCSTR)"Cut Region");
AppendMenu(pop, MF_STRING, COPY_CHOICE, (LPCSTR)"Copy Region");
AppendMenu(pop, MF_STRING, PASTE_CHOICE, (LPCSTR)"Paste");
AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP,
(UINT)pop, (LPCSTR)"Edit");
/* WINDOW
*/
pop = s_menu[WINDOWM] = CreatePopupMenu();
AppendMenu(pop, MF_STRING, s_choices++, function_name(usebuffer));
AppendMenu(pop, MF_STRING, s_choices++, function_name(killbuffer));
AppendMenu(pop, MF_STRING, s_choices++, function_name(listbuffers));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, s_choices++, function_name(nextwind));
AppendMenu(pop, MF_STRING, s_choices++, function_name(prevwind));
AppendMenu(pop, MF_STRING, s_choices++, function_name(splitwind));
AppendMenu(pop, MF_STRING, s_choices++, function_name(onlywind));
AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, (UINT)pop,
(LPCSTR)"Window");
/* EXEC
*/
pop = s_menu[EXECM] = CreatePopupMenu();
AppendMenu(pop, MF_STRING, s_choices++, function_name(windowprog));
AppendMenu(pop, MF_STRING, s_choices++, function_name(spawncli2));
AppendMenu(pop, MF_STRING, s_choices++, function_name(spawncli));
AppendMenu(pop, MF_SEPARATOR, 0, 0L);
AppendMenu(pop, MF_STRING, s_choices++, function_name(sysmake));
AppendMenu(pop, MF_STRING, s_choices++, function_name(makeerror));
AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, (UINT)pop,
"Execute");
/* HELP
*/
pop = s_menu[HELPM] = CreatePopupMenu();
AppendMenu(pop, MF_STRING, HELP_APROPOS,
function_name(apropos_command));
AppendMenu(pop, MF_STRING, HELP_ABOUT, "about...");
AppendMenu(s_menu[PARENT], MF_ENABLED | MF_POPUP, (UINT)pop,
(LPCSTR)"Help");
}
SetMenu(g_hWnd, s_menu[PARENT]);
}
DrawMenuBar(g_hWnd);
}
static void chooseColor(wParam)
WPARAM wParam;
{
CHOOSECOLOR colors;
COLORREF extra[16];
BOOL s;
/* Use special common dialog for chosing color. Note
* that I didn't feel like doing the work of managing
* special mixed colors; you get the ones windows gives
* you. Note also that you can choose non-pure colors
* and on displays with limited colors, it looks crummy
*/
memset(&colors, 0, sizeof(colors));
colors.lStructSize = sizeof(CHOOSECOLOR);
colors.hwndOwner = g_hWnd;
colors.rgbResult = (wParam == TCOLOR_CHOICE ?
GetForeColor() : (wParam == CCOLOR_CHOICE ?
GetHighColor() : GetBackColor()));
colors.Flags |= CC_RGBINIT | CC_PREVENTFULLOPEN;
colors.lpCustColors = extra; /* Crash if this is NULL, even
* though the flag does not say to use
* them. Bogus that it is required.. */
EnableWindow(g_hWnd, FALSE);
s = ChooseColor(&colors);
EnableWindow(g_hWnd, TRUE);
SetActiveWindow(g_hWnd);
if (s)
{
if (wParam == TCOLOR_CHOICE)
SetForeColor(colors.rgbResult);
else if (wParam == WCOLOR_CHOICE)
SetBackColor(colors.rgbResult);
else if (wParam == CCOLOR_CHOICE)
SetHighColor(colors.rgbResult);
ExtendedFunction(function_name(myrefresh));
}
}
/* Wrappers to get to support from menu
*/
int NewFont(f, n)
int f, n;
{
WindowNewFont();
return(TRUE);
}
int NewTextColor(f, n)
int f, n;
{
chooseColor(TCOLOR_CHOICE);
return(TRUE);
}
int NewTouchedTextColor(f, n)
int f, n;
{
chooseColor(CCOLOR_CHOICE);
return(TRUE);
}
int NewWindowColor(f, n)
int f, n;
{
chooseColor(WCOLOR_CHOICE);
return(TRUE);
}
#endif /** JAM **/